﻿using UnityEngine;
using System.Collections;
using System.ComponentModel;

enum PlayerState { Enabled, Disabled };
enum PlayerStatus { Idle, MovinUp, MovingDown, Sinking, Crashed };

public class PlayerManager : MonoBehaviour
{

    public float framesPerSecond;

    private PlayerStatus playerStatus;
    private PlayerState playerState;

    public float maxHeight;                                              //Minimum depth
    public float minHeight;						                        //Maximum depth
    public float maxRotation;						                    //The maximum rotation of the submarine

    private float distanceToBottom;                                        //The current distance to the maximum depth
    private float distanceToTop;                                        //The current distance to the minimum depth

    private static float Xspeed;
    private float Yspeed;                                                //The actual vertical speed of the submarine
    public float downSpeedFactor = 0.7f;
    private float newYspeed;						                        //The new speed of the submarine, used at the edges

    private float rotationDiv;										    //A variable used to calculate rotation
    private Vector3 newRotation;	                                    //Stores the new rotation angles

    public float maxVerticalSpeed;					                    //The maximum vertical speed
    public float depthEdge;					                            //The edge fo the smoothing zone (minDepth- depthEdge and maxDepth - depthEdge)

    private Vector2 startingPos;                                        //Holds the starting position of the submarine

    private float distance;
    private Animator animator;

    // Use this for initialization
    void Start()
    {
        //DebugStreamer.messages.Add("PlayerManager.Start");
        System.Console.WriteLine("PlayerManager.Start");
        animator = this.GetComponent<Animator>();

        newRotation = new Vector3();

        playerStatus = PlayerStatus.MovingDown;
        playerState = PlayerState.Enabled;
        Yspeed = -5;
        Xspeed = 5;
        distance = 0;

        OnSpeedChanged(Xspeed);
    }

    // Update is called once per frame
    void Update()
    {
        animator.SetBool("IsFlying", playerStatus == PlayerStatus.MovinUp);

        if (playerState == PlayerState.Enabled)
        {
            if (playerStatus == PlayerStatus.MovingDown || playerStatus == PlayerStatus.MovinUp)
            {
                //Calculate player movement
                CalculateMovement();

                //Move and rotate the submarine
                MoveAndRotate();
            }
            else if (playerStatus == PlayerStatus.Sinking)
            {
                Sink();
            }
        }
        updateDistance();
    }

    private void updateDistance()
    {
        distance += Time.deltaTime * Xspeed;
    }

    public void UpdateInput(bool inputActive)
    {
        if (playerStatus == PlayerStatus.Sinking || playerStatus == PlayerStatus.Crashed)
            return;

        if (playerStatus == PlayerStatus.Idle || playerStatus == PlayerStatus.MovingDown || inputActive)
            playerStatus = PlayerStatus.MovinUp;
        else if (playerStatus == PlayerStatus.MovinUp)
            playerStatus = PlayerStatus.MovingDown;
    }

    //Calculate movement based on input
    private void CalculateMovement()
    {
        //If the sub is moving up
        if (playerStatus == PlayerStatus.MovinUp)
        {
            MoveUp();
        }
        //If the sub is moving down
        else
        {
            MoveDown();
        }
    }

    private void MoveUp()
    {
        //Increase speed
        Yspeed += Time.deltaTime * maxVerticalSpeed;

        //If the sub is too close to the minDepth
        if (this.transform.position.y > maxHeight)
        {
            //Calculate maximum speed at this depth (without this, the sub would leave the gameplay are)
            newYspeed = maxVerticalSpeed * (maxHeight - this.transform.position.y) / depthEdge;

            //If the newSpeed is lesser the the current speed
            if (newYspeed < Yspeed)
            {
                //Make newSpeed the current speed
                Yspeed = newYspeed;
            }
        }

        //If the sub is too close to the maxDepth
        if (this.transform.position.y < minHeight)
        {
            //playerStatus = PlayerStatus.Idle;
            //Calculate maximum speed at this depth (without this, the sub would leave the gameplay are)
            newYspeed = maxVerticalSpeed * (minHeight - this.transform.position.y) / depthEdge;

            //If the newSpeed is greater the the current speed
            if (newYspeed > Yspeed)
            {
                //Make newSpeed the current speed
                Yspeed = newYspeed;
            }
        }

    }

    private void MoveDown()
    {
        //Decrease speed
        //speed -= Time.deltaTime * maxVerticalSpeed;
        Yspeed -= Time.deltaTime * maxVerticalSpeed;

        if (this.transform.position.y > maxHeight)
        {
            //Calculate maximum speed at this depth (without this, the sub would leave the gameplay are)
            newYspeed = maxVerticalSpeed * (maxHeight - this.transform.position.y) / depthEdge;

            //If the newSpeed is lesser the the current speed
            if (newYspeed < Yspeed)
            {
                //Make newSpeed the current speed
                Yspeed = newYspeed;
            }
        }

        //If the sub is too close to the maxDepth
        if (this.transform.position.y < minHeight)
        {
            //playerStatus = PlayerStatus.Idle;
            //Calculate maximum speed at this depth (without this, the sub would leave the gameplay are)
            newYspeed = maxVerticalSpeed * (minHeight - this.transform.position.y) / depthEdge;

            //If the newSpeed is greater the the current speed
            if (newYspeed > Yspeed)
            {
                //Make newSpeed the current speed
                Yspeed = newYspeed * downSpeedFactor;
            }
        }

    }

    private void MoveAndRotate()
    {
        //Calculate new rotation
        //newRotation.z = speed / rotationDiv;

        //Apply new rotation and position
        //  this.transform.eulerAngles = newRotation;
        this.transform.position += Vector3.up * Yspeed * Time.deltaTime;
    }
    //Sinks the submarine until it crashes to the sand
    private void Sink()
    {
        float crashDepth = minHeight - 0.8f;
        float crashDepthEdge = 0.5f;

        float distance = this.transform.position.y - crashDepth;

        //If the sub is too close to minDepth
        if (distanceToTop < depthEdge)
        {
            //Calculate maximum speed at this depth (without this, the sub would leave the gameplay are)
            newYspeed = maxVerticalSpeed * (maxHeight - this.transform.position.y) / depthEdge;

            //If the newSpeed is greater the the current speed
            if (newYspeed < Yspeed)
                //Make newSpeed the current speed
                Yspeed = newYspeed;
        }
        //If the distance to the sand is greater than 0.1
        if (distance > 0.1f)
        {
            //Reduce speed
            Yspeed -= Time.deltaTime * maxVerticalSpeed * 0.6f;

            //If the distance to the sand smaller than the crashDepthEdge
            if (distance < crashDepthEdge)
            {
                //Calculate new speed for impact
                newYspeed = maxVerticalSpeed * (crashDepth - this.transform.position.y) / crashDepthEdge;

                //If newSpeed is greater than speed
                if (newYspeed > Yspeed)
                    //Apply new speed to speed
                    Yspeed = newYspeed;
            }

            //Apply the above to the submarine
            MoveAndRotate();

            //If distance to sand smaller than 0.2
            if (distance < 0.25f)
            {
                //Enable smoke emission
                //smoke.enableEmission = true;
            }
        }
        //If the distance to the sand is smaller than 0.1
        else
        {
            //Disable this function from calling, and stop the level
            playerStatus = PlayerStatus.Crashed;
            // levelManager.StopLevel();

            //Disable the smoke
            //StartCoroutine(FunctionLibrary.CallWithDelay(DisableSmoke, 2));
        }
    }

    public float getDistance()
    {
        return distance;
    }

    public static float getXspeed()
    {
        return Xspeed;
    }



    // Indicates that the level switch is starting
    public delegate void SpeedChanged(float speed);
    public static event SpeedChanged OnSpeedChanged;

    public void IncreaseSpeed(float speed)
    {
        Xspeed += speed;

        OnSpeedChanged(Xspeed);

    }

}
